import React, { Component } from 'react';
import {
Typography, FormControl, Select, MenuItem,
InputLabel, Button, Switch, Tooltip
} from "@material-ui/core";
import { Slider } from '@material-ui/lab';
import "../ParamView.css";
import { objectiveTypes, loadStates } from '../../LucidJS/src/optvis/renderer.js';
import PlayButtonGroup from "./PlayButtonGroup"
import { fillCanvasPixelsWithRgbAndAlpha, fillCanvasPixelsWithGreyAndAlpha }
from '../../DrawingHelper.js';
import ActivationView from "../ActivationView";
import NeuronSelectorView from "../NeuronSelectorView";
import SecondaryPreview from "../SecondaryPreview";
import ToggleButton from '@material-ui/lab/ToggleButton';
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
import { scdryPrvMode } from '../../BlogpostHome';
const objectives = Object.entries(
objectiveTypes).map((keyAndValue) => keyAndValue[1]);
const selectableParameters = [
{type: "channel", layer: "conv2d1", channel: 58},
{type: "channel", layer: "mixed3a_3x3", channel: 4},
{type: "channel", layer: "mixed3a_3x3", channel: 85},
{type: "channel", layer: "mixed4a_pool_reduce", channel: 16},
{type: "channel", layer: "mixed4a_pool_reduce", channel: 32},
{type: "channel", layer: "mixed4a_pool_reduce", channel: 48},
{type: "channel", layer: "mixed5a_1x1", channel: 9},
]
/**
* Component that contains controls for changing the optimization objective.
*/
class ObjectiveDemo extends Component {
constructor(props) {
super(props);
this.state = {
selectedToggleButton: -1,
}
this.imageCanvas = React.createRef();
this.imageCanvasSecondary = React.createRef();
}
render() {
let w = this.props.inputSize;
let h = this.props.inputSize;
let canvases = null;
window.requestAnimationFrame(() => {
if (this.imageCanvas.current && this.props.currentInput) {
const [b, inW, inH, ch] = this.props.inputShape;
this.drawPixelsToCanvas(this.props.currentInput,
this.imageCanvas.current, w, h, ch === 3 ? true : false);
}
if(this.imageCanvasSecondary.current && this.props.lastInput) {
const width = this.props.inputSize;
const height = this.props.inputSize;
const [b, inW, inH, ch] = this.props.lastInputShape;
this.imageCanvasSecondary.current.getContext("2d").putImageData(
this.getImageDataFromPixelData(
this.props.lastInput, width, height, ch===3 ? true : false), 0, 0
)
}
});
const prevWidth = 200;
const ch = this.state.selectedChannel;
const toggleButtonTitle = (ind) => {
const params = selectableParameters[ind];
const l = params.layer.split('_')[0];
const ch = params.channel;
const t = params.type;
if(t === 'channel') {
return l+ ": " + ch;
} else {
return l;
}
}
return (
<div style={{
display: "flex", flexDirection: "column",
height: "100%", width: "100%",
}}>
<ToggleButtonGroup style={{
width: "100%"
}}
size="large" value={this.state.selectedToggleButton} exclusive
onChange={(e, v) => {
this.setState({selectedToggleButton: v})
const newObj = selectableParameters[v];
this.props.changedObjectiveToggle(newObj);
}}>
{
selectableParameters.map((el, i) => {
return (
<ToggleButton value={i}>
{toggleButtonTitle(i)}
</ToggleButton>)
})
}
</ToggleButtonGroup>
<div style={{
display: "flex", flexDirection: "column",
height: "100%", width: "100%",
}}>
<div className="paramContainer" style={{
height: "50%"
}}>
<div style={{
width: "60%", height: "100%", padding: "5px",
display: "flex", flexDirection: "row",
justifyContent: "space-evenly"
}}>
<div className="inlineParamSettingsColumn">
<div className="inlineParamGroup" style={
{
display: "flex", flexDirection: "row",
justifyContent: "center"
}
}>
<PlayButtonGroup
canOptimize={this.props.canOptimize}
isOptimizing={this.props.isOptimizing}
onOptimize={this.props.onOptimize}
onStep={this.props.onStep}
stopOptimization={this.props.stopOptimization}
onReset={this.props.onReset} />
</div>
</div>
<div className="inlineParamSettingsColumn">
<FormControl className="menu" style={{
flexGrow: "0"
}}>
<InputLabel>Objective type</InputLabel>
<Select
value={this.props.objectiveType}
error={false}
onChange={(event) => {
this.props.changedObjective(event.target.value);
}}>
{objectives.map((objective, index) => {
return <MenuItem value={objective}>{objective}</MenuItem>
})}
</Select>
</FormControl>
< div className="splitParamGroup">
<Typography className="wholeWidth">Negative</Typography>
<Switch className="wholeWidth"
checked={this.props.negative}
onChange={(e, v) =>
this.props.changedNegative(v)}></Switch>
</div>
<div className="paramGroup">
<Typography
className="sliderLabel">Jitter: {
this.props.jitter}</Typography>
<Slider
className="slider"
min={0}
max={12}
step={1}
value={this.props.jitter}
aria-labelledby="label"
onChange={(e, v) =>
this.props.changedJitter(v)}
/>
</div>
<div className="paramGroup">
<Typography
className="sliderLabel">Learning Rate: {
this.props.learningRates[
this.props.learningRate]}</Typography>
<Slider
className="slider"
min={0}
max={10}
step={1}
value={this.props.learningRate}
aria-labelledby="label"
onChange={(e, v) =>
this.props.changedLearningRate(v)
}
/>
</div>
</div>
</div>
<div style={{ width: "40%", height: "100%", padding: "5px" }}>
<div className="optimPreviewCanvasContainer"
style={{ height: '100%' }}>
<div>
<div style={{
display: 'flex', justifyContent: 'center',
alignItems: 'center'
}}>
<canvas className="optimPreviewCanvas"
ref={this.imageCanvas}
width={this.props.inputSize}
height={this.props.inputSize}
style={{ width: prevWidth, height: prevWidth }} />
</div>
</div>
</div>
</div>
</div>
<div className="paramContainer" style={{
height: "50%"
}}>
<div style={{
width: "60%", padding: "5px"
}}>
<ActivationView
activationShape={this.props.activationShape}
channelNumber={this.props.channelNumber}
selectedChannel={this.props.selectedChannel}
activations={this.props.activations}
onClickFeatureMap={(selectedInd) => {
this.props.channelChanged(selectedInd);
}}
/>
</div>
<div style={{
width: "40%", height: "100%", padding: "5px"
}}>
<div className="optimPreviewCanvasContainer"
style={{ height: '100%' }}>
<div>
<div style={{
display: 'flex', justifyContent: 'center',
alignItems: 'center'
}}></div>
<SecondaryPreview
enabledModes={[
scdryPrvMode.COMPARE,
scdryPrvMode.NEURON
]}
prvMode={this.props.prvMode}
prvModeChanged={this.props.prvModeChanged}
inputSize={this.props.inputSize}
prevWidth={prevWidth}
imageCanvasSecondary={this.imageCanvasSecondary}
className={"secondaryPreviewLayer"}
selectedLayer={this.props.selectedLayer}
selectedChannel={this.props.selectedChannel}
activations={this.props.detailActivations}
activationShape={this.props.activationShape}
selectedNeuron={this.props.selectedNeuron}
neuronChanged={this.props.neuronChanged}
style={{
width: prevWidth,
height: prevWidth
}} />
</div>
</div>
</div>
</div>
</div>
</div>);
}
drawPixelsToCanvas(pixelData, canvas, w, h, rgb, channel = 0) {
let canvCtx = canvas.getContext("2d");
const cw = canvas.width;
const ch = canvas.height;
const wratio = cw / w;
const hratio = ch / h;
if (w !== cw || h !== ch) {
let tempCanvas = document.createElement("canvas");
tempCanvas.width = w;
tempCanvas.height = h;
let tempCtx = tempCanvas.getContext('2d');
let imData = tempCtx.createImageData(w, h);
if (rgb) {
fillCanvasPixelsWithRgbAndAlpha(imData.data, pixelData, w, h, channel);
} else {
fillCanvasPixelsWithGreyAndAlpha(imData.data, pixelData, w, h, channel);
}
tempCtx.putImageData(imData, 0, 0);
canvCtx.scale(wratio, hratio);
canvCtx.drawImage(tempCanvas, 0, 0);
canvCtx.scale(1 / wratio, 1 / hratio);
} else {
let imData = canvCtx.createImageData(w, h);
if (rgb) {
fillCanvasPixelsWithRgbAndAlpha(imData.data, pixelData, w, h, channel);
} else {
fillCanvasPixelsWithGreyAndAlpha(imData.data, pixelData, w, h, channel);
}
canvCtx.putImageData(imData, 0, 0);
}
}
getImageDataFromPixelData(pixelData, w, h, rgb, mult=1, channel=0){
let tempCanvas = document.createElement("canvas");
tempCanvas.width = w;
tempCanvas.height = h;
let tempCtx = tempCanvas.getContext('2d');
let imData = tempCtx.createImageData(w, h);
channel = 0;
if(rgb){
fillCanvasPixelsWithRgbAndAlpha(
imData.data, pixelData, w, h, channel, mult);
} else {
fillCanvasPixelsWithGreyAndAlpha(
imData.data, pixelData, w, h, channel, mult);
}
return imData
}
}
export default ObjectiveDemo;